// 
//  Copyright 2011  reda
// 
//    Licensed under the Apache License, Version 2.0 (the "License");
//    you may not use this file except in compliance with the License.
//    You may obtain a copy of the License at
// 
//        http://www.apache.org/licenses/LICENSE-2.0
// 
//    Unless required by applicable law or agreed to in writing, software
//    distributed under the License is distributed on an "AS IS" BASIS,
//    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//    See the License for the specific language governing permissions and
//    limitations under the License.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using ManiacMusicManager.Data.Core;
using ManiacMusicManager.Data.DAO.Ifaces;
using ManiacMusicManager.Data.Utils;
using NHibernate;
namespace ManiacMusicManager.Data.DAO.Wrapper
{
	/// <summary>
	/// Cette classe est destinée à encapsuler un DAO du type <typeparamref name="T"/> dans un <see cref="IDAO<Entity>"/>
	/// </summary>
	internal class DAOWrapper<T> : IDAO<Entity>
		where T : Entity
	{
		#region Construction
		private readonly IDAO<T> _wrapped;
		
		public DAOWrapper (IDAO<T> dao)
		{
			if (dao == null)
				throw new ArgumentNullException ("dao");
			
			this._wrapped = dao;
		}
		
		public IDAO<Entity> Wrap ()
		{
			return this;
		}
		
		public IEnumerable<Entity> MakeSafe (IEnumerable<Entity> list)
		{
			return Convert(this._wrapped.MakeSafe(Convert(list)));
		}
		#endregion
		
		#region Convertisseurs
		private Expression<Func<T, D>> Convert<D>(Expression<Func<Entity, D>> query) {
			var param = Expression.Parameter(typeof(T), "e");
			Expression<Func<T, Entity>> convert = (T e) => e;
			var converted = Expression.Invoke(convert, param);
			var result = Expression.Invoke(query, converted);
			
			return result as Expression<Func<T, D>>;
		}
		
		private IQueryable<T> Convert(IQueryable<Entity> query) {
			return query.Cast<T>();
		}
		
		private IQueryable<Entity> Convert(IQueryable<T> query) {
			return query.Cast<Entity>();
		}
		
		private IEnumerable<T> Convert(IEnumerable<Entity> list) {
			return list.Cast<T>();
		}
		
		private IEnumerable<Entity> Convert(IEnumerable<T> list) {
			return list.Cast<Entity>();
		}
		#endregion

		#region IDAO[Entity] implementation
		public void Clear ()
		{
			this._wrapped.Clear();
		}
		
		public int Save (Entity obj)
		{
			return this._wrapped.Save(obj as T);
		}

		public void Update (Entity obj)
		{
			this._wrapped.Update(obj as T);
		}

		public void Delete (Entity obj)
		{
			this._wrapped.Delete(obj as T);
		}

		public void Delete (int id)
		{
			this._wrapped.Delete(id);
		}

		public void SaveOrUpdate (Entity obj)
		{
			this._wrapped.SaveOrUpdate(obj as T);
		}

		public Entity Get (int id)
		{
			return this._wrapped.Get(id);
		}

		public Entity GetOneResult (IEnumerable<Entity> coll)
		{
			return this._wrapped.GetOneResult(Convert(coll));
		}

		public IQueryable<Entity> Linq ()
		{
			return Convert(this._wrapped.Linq());
		}

		public IEnumerable<Entity> SelectByQuery (IQueryable<Entity> query)
		{
			return Convert(this._wrapped.SelectByQuery(Convert(query)));
		}

		public Entity GetByQuery (IQueryable<Entity> query)
		{
			return this._wrapped.GetByQuery(Convert(query));
		}

		public IQueryable<Entity> FilterOnText (Expression<Func<Entity, string>> strGet, string value, Utils.StringSearchOptions options)
		{
			return Convert(this._wrapped.FilterOnText(Convert<string>(strGet), value, options));
		}

		public IQueryable<Entity> FilterOnInteger (Expression<Func<Entity, int>> intGet, int minValue, int maxValue)
		{
			return Convert(this._wrapped.FilterOnInteger(Convert<int>(intGet), minValue, maxValue));
		}

		public IQueryable<Entity> FilterOnStringList (Expression<Func<Entity, IEnumerable<string>>> lstGet, string value, Utils.StringSearchOptions options)
		{
			return Convert(this._wrapped.FilterOnStringList(Convert<IEnumerable<string>>(lstGet), value, options));
		}

		public IQueryable<Entity> FilterOnInteger (Expression<Func<Entity, int>> intGet, int value)
		{
			return Convert(this._wrapped.FilterOnInteger(Convert<int>(intGet), value));
		}

		public IEnumerable<Entity> SelectByName (string name, StringSearchOptions options)
		{
			return Convert(this._wrapped.SelectByName(name, options));
		}

		public IEnumerable<Entity> SelectByName (string name)
		{
			return Convert(this._wrapped.SelectByName(name));
		}

		public Entity GetByName (string name)
		{
			return this._wrapped.GetByName(name);
		}

		public IEnumerable<Entity> SelectByComment (params string[] mots)
		{
			return Convert(this._wrapped.SelectByComment(mots));
		}

		#endregion

//		#region ISessionHolder implementation
//		public ISession GetSession ()
//		{
//			return this._wrapped.sessionHolder.GetSession();
//		}
//
//		public void BeginSafeBlock ()
//		{
//			this._wrapped.sessionHolder.BeginSafeBlock();
//		}
//
//		public void EndSafeBlock ()
//		{
//			this._wrapped.sessionHolder.EndSafeBlock();
//		}
//		#endregion
		
		public void Dispose ()
		{
			this._wrapped.Dispose();
		}
	}
}

